home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / mac / macdraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  28.7 KB  |  1,030 lines  |  [TEXT/R*ch]

  1. /* Low-level drawing for the Mac interface to Xconq.
  2.    Copyright (C) 1992, 1993, 1994, 1995, 1996 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. /* Routines in this file should rarely, if ever, call run_warning,
  10.    since the exposure following the handling of the warning dialog
  11.    can cause the same warning to appear again, and the player can
  12.    get pretty wedged. */
  13.  
  14. #include "conq.h"
  15. #define wind_dir(w) ((w) & 0x07)
  16. #define wind_force(w) ((w) >> 3)
  17. #include "macconq.h"
  18.  
  19. PolyHandle polygons[NUMPOWERS];
  20. int lastpolyx[NUMPOWERS], lastpolyy[NUMPOWERS];
  21.  
  22. RgnHandle cellrgns[NUMPOWERS];
  23. int lastcellrgnx[NUMPOWERS], lastcellrgny[NUMPOWERS];
  24. RgnHandle gridcellrgns[NUMPOWERS];
  25. int lastgridcellrgnx[NUMPOWERS], lastgridcellrgny[NUMPOWERS];
  26.  
  27. RgnHandle cellrgns30[NUMPOWERS];
  28. int lastcellrgnx30[NUMPOWERS], lastcellrgny30[NUMPOWERS];
  29. RgnHandle gridcellrgns30[NUMPOWERS];
  30. int lastgridcellrgnx30[NUMPOWERS], lastgridcellrgny30[NUMPOWERS];
  31.  
  32. RgnHandle cellrgns15[NUMPOWERS];
  33. int lastcellrgnx15[NUMPOWERS], lastcellrgny15[NUMPOWERS];
  34. RgnHandle gridcellrgns15[NUMPOWERS];
  35. int lastgridcellrgnx15[NUMPOWERS], lastgridcellrgny15[NUMPOWERS];
  36.  
  37. int numwindsicns = 0;
  38.  
  39. Handle windsicnhandle[5];
  40.  
  41. int numblastsicns = 0;
  42.  
  43. Handle blastsicnhandle[3];
  44.  
  45. static Image **best_terrain_images = NULL;
  46.  
  47. static Image **best_unseen_images = NULL;
  48.  
  49. /* Draw an image of the given type of unit in the given rectangle, possibly adding
  50.    an emblem if requested. */
  51.  
  52. void
  53. draw_unit_image(WindowPtr win, int sx, int sy, int sw, int sh, int u, int e, int mod)
  54. {
  55.     int ex, ey, ew, eh;
  56.     Rect srcrect, imagerect;
  57.     BitMap bm, *winbits;
  58.     Image *uimg;
  59.     MacImage *macuimg;
  60.  
  61.     /* Filter out very small images. */
  62.     if (sw <= 1)
  63.       return;
  64.     imagerect.top = sy;  imagerect.left = sx;
  65.     imagerect.bottom = imagerect.top + sh;  imagerect.right = imagerect.left + sw;
  66.     if (sw <= 4) {
  67.         /* (should draw in a distinctive color if one is available) */
  68.         FillRect(&imagerect, QDPat(black));
  69.         return;
  70.     }
  71.     uimg = best_image(uimages[u], sw, sh);
  72.     /* There should always be *some* image to display. */
  73.     if (uimg && uimg->hook) {
  74.         macuimg = (MacImage *) uimg->hook;
  75.         winbits = &(((GrafPtr) win)->portBits);
  76.         if (macuimg->monopict != nil) {
  77.             DrawPicture(macuimg->monopict, &imagerect);
  78.         } else if (macuimg->colricon != nil
  79.                    && (minscreendepth > 1
  80.                           || (macuimg->monoicon == nil && macuimg->monosicn == nil))) {
  81.             PlotCIcon(&imagerect, (CIconHandle) macuimg->colricon);
  82.         } else if (macuimg->monoicon != nil) {
  83.             SetRect(&srcrect, 0, 0, 32, 32);
  84.             bm.rowBytes = 4;
  85.             bm.bounds = srcrect;
  86.             if (macuimg->maskicon != nil) {
  87.                 bm.baseAddr = *(macuimg->maskicon);
  88.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  89.             } else {
  90.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  91.                 FillRect(&imagerect, QDPat(white));
  92.             }
  93.             bm.baseAddr = *(macuimg->monoicon);
  94.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  95.         } else if (macuimg->monosicn != nil) {
  96.             SetRect(&srcrect, 0, 0, 16, 16);
  97.             if (sw > 64) {
  98.                 InsetRect(&imagerect, sw / 4, sh / 4);
  99.             }
  100.             bm.rowBytes = 2;
  101.             bm.bounds = srcrect;
  102.             if (macuimg->masksicn != nil) {
  103.                 bm.baseAddr = *(macuimg->masksicn);
  104.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  105.             } else {
  106.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  107.                 FillRect(&imagerect, QDPat(white));
  108.             }
  109.             bm.baseAddr = *(macuimg->monosicn);
  110.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  111.         } else {
  112.             FillRect(&imagerect, QDPat(black));
  113.         }
  114.     } else {
  115.         /* Rather a crummy substitute. */
  116.         FillRect(&imagerect, QDPat(black));
  117.     }
  118.     if (mod != 0) {
  119.         gray_out_rect(&imagerect);
  120.     }
  121.     /* Now draw a side emblem if asked for. */
  122.     if (between(0, e, numsides)) {
  123.         if (uimg &&
  124.             uimg->embedname &&
  125.             side_n(e) &&
  126.             side_n(e)->emblemname &&
  127.             strcmp(uimg->embedname, side_n(e)->emblemname) == 0) {
  128.             /* Correct emblem is part of the unit's image, don't need to draw. */
  129.         } else {
  130.             /* Get the size of the emblem, either from the image or by computing
  131.                a reasonable default. */
  132.             if (uimg && uimg->embedw > 0 && uimg->embedh > 0) {
  133.                 ew = uimg->embedw;  eh = uimg->embedh;
  134.             } else {
  135.                 ew = min(sw, max(8, sw / 4));  eh = min(sh, max(8, sh / 4));
  136.             }
  137.             /* Position the emblem, either explicitly, or default to UR corner
  138.                (note that we need the emblem's width to do this) */
  139.             if (uimg && uimg->embedx >= 0 && uimg->embedy >= 0) {
  140.                 ex = uimg->embedx;  ey = uimg->embedy;
  141.             } else {
  142.                 ex = sw - ew;  ey = 0;
  143.             }
  144.             /* Do the drawing proper. */
  145.             draw_side_emblem(win, sx + ex, sy + ey, ew, eh, e, plain_emblem);
  146.         }
  147.     }
  148. }
  149.  
  150. /* Draw a given side id's emblem. Uses the current GrafPort. */
  151.  
  152. void
  153. draw_side_emblem(WindowPtr win, int ex, int ey, int ew, int eh, int e, int style)
  154. {
  155.     int actualw, actualh;
  156.     Rect srcrect, imagerect, shadowrect;
  157.     BitMap bm, *winbits;
  158.     CIconHandle cicnhandle;
  159.     Image *eimg;
  160.     MacImage *maceimg;
  161.  
  162.     /* Filter out very small images. */
  163.     if (ew <= 1)
  164.       return;
  165.     if (ew <= 2) {
  166.         /* (should draw in a distinctive color if one is available) */
  167.         /* FillRect(&imagerect, QDPat(black)); */
  168.         return;
  169.     }
  170.     eimg = best_image(eimages[e], ew, eh);
  171.     imagerect.top = ey;  imagerect.left = ex;
  172.     actualw = eimg->w;  actualh = eimg->h;
  173.     if (ew >= actualw * 2 && eh >= actualh * 2) {
  174.         actualw *= 2;  actualh *= 2;
  175.     }
  176.     if (ew >= actualw * 2 && eh >= actualh * 2) {
  177.         actualw *= 2;  actualh *= 2;
  178.     }
  179.     if (actualw < ew)
  180.       ew = actualw;
  181.     if (actualh < eh)
  182.       eh = actualh;
  183.     imagerect.bottom = imagerect.top + eh;  imagerect.right = imagerect.left + ew;
  184.     /* If an image is available, display it, otherwise do nothing. */
  185.     if (eimg && eimg->hook) {
  186.         maceimg = (MacImage *) eimg->hook;
  187.         winbits = &(((GrafPtr) win)->portBits);
  188.         if (maceimg->monopict != nil) {
  189.             /* (should use a mask and shadow here somehow) */
  190.             DrawPicture(maceimg->monopict, &imagerect);
  191.         } else if (maceimg->colricon != nil
  192.                    && (minscreendepth > 1
  193.                           || (maceimg->monoicon == nil && maceimg->monosicn == nil))) {
  194.             cicnhandle = (CIconHandle) maceimg->colricon;
  195.             if (style == shadow_emblem) {
  196.                 SetRect(&srcrect, 0, 0, eimg->w, eimg->h);
  197.                 shadowrect = imagerect;
  198.                 OffsetRect(&shadowrect, (ew < 16 ? 1 : 2), (ew < 16 ? 1 : 2));
  199.                 bm.rowBytes = (*cicnhandle)->iconBMap.rowBytes;
  200.                 bm.bounds = srcrect;
  201.                 if (bm.rowBytes > 0) {
  202.                     bm.baseAddr = (char *) (*cicnhandle)->iconMaskData;
  203.                 }
  204.                 if (hasColorQD) {
  205.                     RGBColor tmpcolor;
  206.  
  207.                     tmpcolor.red = tmpcolor.green = tmpcolor.blue = 49000;
  208.                     RGBForeColor(&tmpcolor);
  209.                     if (bm.rowBytes > 0) {
  210.                         CopyBits(&bm, winbits, &srcrect, &shadowrect, srcCopy, nil);
  211.                     } else {
  212.                         PaintRect(&shadowrect);
  213.                     }
  214.                     /* Restore the previous color. */
  215.                     tmpcolor.red = tmpcolor.green = tmpcolor.blue = 0;
  216.                     RGBForeColor(&tmpcolor);
  217.                 } else {
  218.                     FillRect(&shadowrect, QDPat(gray));
  219.                 }
  220.             }
  221.             PlotCIcon(&imagerect, cicnhandle);
  222.         } else if (maceimg->monoicon != nil) {
  223.             SetRect(&srcrect, 0, 0, 32, 32);
  224.             bm.rowBytes = 4;
  225.             bm.bounds = srcrect;
  226.             if (maceimg->maskicon != nil) {
  227.                 bm.baseAddr = *(maceimg->maskicon);
  228.                 if (style == shadow_emblem) {
  229.                 }
  230.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  231.             } else {
  232.                 /* Use emblem bbox as default mask. */
  233.                 if (style == shadow_emblem) {
  234.                 }
  235.                 FillRect(&imagerect, QDPat(white));
  236.             }
  237.             bm.baseAddr = *(maceimg->monoicon);
  238.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  239.         } else if (maceimg->monosicn != nil) {
  240.             SetRect(&srcrect, 0, 0, 16, 16);
  241.             bm.rowBytes = 2;
  242.             bm.bounds = srcrect;
  243.             if (maceimg->masksicn != nil) {
  244.                 bm.baseAddr = *(maceimg->masksicn);
  245.                 if (style == shadow_emblem) {
  246.                 }
  247.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  248.             } else {
  249.                 /* Use emblem bbox as default mask. */
  250.                 if (style == shadow_emblem) {
  251.                 }
  252.                 FillRect(&imagerect, QDPat(white));
  253.             }
  254.             bm.baseAddr = *(maceimg->monosicn);
  255.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  256.         } else {
  257.             FillRect(&imagerect, QDPat(black));
  258.         }
  259.     }
  260. }
  261.  
  262. void
  263. calc_best_terrain_images()
  264. {
  265.     int p, t;
  266.     Image *timg;
  267.  
  268.     best_terrain_images = (Image **) xmalloc(NUMPOWERS * numttypes * sizeof(Image *));
  269.     for_all_terrain_types(t) {
  270.         for (p = 0; p < NUMPOWERS; ++p) {
  271.             timg = best_image(timages[t], hws[p], hcs[p]);
  272.             best_terrain_images[p * numttypes + t] = timg;
  273.         }
  274.     }
  275.     best_unseen_images = (Image **) xmalloc(NUMPOWERS * sizeof(Image *));
  276.     if (unseen_image != NULL) {
  277.         for (p = 0; p < NUMPOWERS; ++p) {
  278.             timg = best_image(unseen_image, hws[p], hcs[p]);
  279.             best_unseen_images[p] = timg;
  280.         }
  281.     }
  282. }
  283.  
  284. void
  285. draw_cell_block(int sx, int sy, int n, int power, int t, int t2, int angle)
  286. {
  287.     Rect rect;
  288.     Image *timg;
  289.     MacImage *mactimg;
  290.     RGBColor cellcolor, oldcolor;                
  291.  
  292.     rect.left = sx;  rect.top = sy;
  293.     rect.right = rect.left + n * hws[power];  rect.bottom = rect.top + hcs[power];
  294.     if (angle == 30) {
  295.         rect.bottom = rect.top + hcs[power] / 2;
  296.     } else if (angle == 15) {
  297.         rect.bottom = rect.top + hcs[power] / 4;
  298.     }
  299.     if (best_terrain_images == NULL)
  300.       calc_best_terrain_images();
  301.     if (t == NONTTYPE)
  302.       timg = best_unseen_images[power];
  303.     else
  304.       timg = best_terrain_images[power * numttypes + t];
  305.     if (timg && timg->hook) {
  306.         mactimg = (MacImage *) timg->hook;
  307.         if (hasColorQD) {
  308.             if (mactimg->colrpat != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
  309.                 FillCRect(&rect, mactimg->colrpat);
  310.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  311.                 /* A solid color is preferable to a b/w pattern. */
  312.                 cellcolor.red   = (tcolors[t]->r) << 8;
  313.                 cellcolor.green = (tcolors[t]->g) << 8;
  314.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  315.                 RGBForeColor(&cellcolor);
  316.                 PaintRect(&rect);
  317.                 /* Restore the previous color. */
  318.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  319.                 RGBForeColor(&oldcolor);
  320.             } else if (mactimg->patdefined) {
  321.                 FillRect(&rect, IMG_PAT(mactimg));
  322.             }
  323.         } else {
  324.             FillRect(&rect, IMG_PAT(mactimg));
  325.         }
  326.     } else {
  327.         /* No image; use a color instead. */
  328.         if (hasColorQD) {
  329.             if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  330.                 cellcolor.red   = (tcolors[t]->r) << 8;
  331.                 cellcolor.green = (tcolors[t]->g) << 8;
  332.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  333.                 RGBForeColor(&cellcolor);
  334.                 PaintRect(&rect);
  335.                 /* Restore the previous color. */
  336.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  337.                 RGBForeColor(&oldcolor);
  338.             } else {
  339.                 /* leave it blank? sigh */
  340.             }
  341.         } else {
  342.             /* leave it blank? sigh */
  343.         }
  344.     }
  345.     /* If any graying/shading was requested, do it. */
  346.     if (t2 < 0) {
  347.         if (t2 == -1) {
  348.             PenPat(QDPat(ltGray));
  349.             PenMode(patOr);
  350.         } else if (t2 == -2) {
  351.             PenPat(QDPat(gray));
  352. /*                PenMode(patBic);  */
  353.             PenMode(notPatOr);
  354.         }
  355.         PaintRect(&rect);
  356.         PenNormal();
  357.     }
  358. }
  359.  
  360. /* Draw the given terrain type into a hexagonal region of the given size and position. */
  361.  
  362. void
  363. draw_hex_region(int sx, int sy, int power, int dogrid, int t, int t2, int angle)
  364. {
  365.     Image *timg;
  366.     MacImage *mactimg;
  367.     RGBColor hexcolor, oldcolor;
  368.     RgnHandle rgn;
  369.  
  370.     if (best_terrain_images == NULL)
  371.       calc_best_terrain_images();
  372.     if (cellrgns[power] == nil)
  373.       make_cell_clip(power);
  374.     if (angle == 30) {
  375.           OffsetRgn(cellrgns30[power], sx - lastcellrgnx30[power], sy - lastcellrgny30[power]);
  376.           lastcellrgnx30[power] = sx;  lastcellrgny30[power] = sy;
  377.           OffsetRgn(gridcellrgns30[power], sx - lastgridcellrgnx30[power], sy - lastgridcellrgny30[power]);
  378.           lastgridcellrgnx30[power] = sx;  lastgridcellrgny30[power] = sy;
  379.         rgn = (dogrid ? gridcellrgns30[power] : cellrgns30[power]);
  380.     } else if (angle == 15) {
  381.           OffsetRgn(cellrgns15[power], sx - lastcellrgnx15[power], sy - lastcellrgny15[power]);
  382.          lastcellrgnx15[power] = sx;  lastcellrgny15[power] = sy;
  383.           OffsetRgn(gridcellrgns15[power], sx - lastgridcellrgnx15[power], sy - lastgridcellrgny15[power]);
  384.           lastgridcellrgnx15[power] = sx;  lastgridcellrgny15[power] = sy;
  385.         rgn = (dogrid ? gridcellrgns15[power] : cellrgns15[power]);
  386.     } else {
  387.           OffsetRgn(cellrgns[power], sx - lastcellrgnx[power], sy - lastcellrgny[power]);
  388.           lastcellrgnx[power] = sx;  lastcellrgny[power] = sy;
  389.           OffsetRgn(gridcellrgns[power], sx - lastgridcellrgnx[power], sy - lastgridcellrgny[power]);
  390.          lastgridcellrgnx[power] = sx;  lastgridcellrgny[power] = sy;
  391.         rgn = (dogrid ? gridcellrgns[power] : cellrgns[power]);
  392.     }
  393.     if (t == NONTTYPE)
  394.       timg = best_unseen_images[power];
  395.     else
  396.       timg = best_terrain_images[power * numttypes + t];
  397.     if (timg && timg->hook) {
  398.         mactimg = (MacImage *) timg->hook;
  399.         if (hasColorQD) {
  400.             if (mactimg->colrpat != nil && (minscreendepth > 1 || !mactimg->patdefined)) {
  401.                 FillCRgn(rgn, mactimg->colrpat);
  402.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  403.                 /* A solid color is preferable to a b/w pattern. */
  404.                 hexcolor.red   = (tcolors[t]->r) << 8;
  405.                 hexcolor.green = (tcolors[t]->g) << 8;
  406.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  407.                 RGBForeColor(&hexcolor);
  408.                 PaintRgn(rgn);
  409.                 /* Restore the previous color. */
  410.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  411.                 RGBForeColor(&oldcolor);
  412.             } else if (mactimg->patdefined) {
  413.                 /* Fall back on the b/w pattern. */
  414.                 FillRgn(rgn, IMG_PAT(mactimg));
  415.             }
  416.         } else {
  417.             FillRgn(rgn, IMG_PAT(mactimg));
  418.         }
  419.     } else {
  420.         if (hasColorQD) {
  421.             if (tcolors[t] != NULL && tcolors[t]->defined && maxscreendepth > 1) {
  422.                 /* Use the solid color. */
  423.                 hexcolor.red   = (tcolors[t]->r) << 8;
  424.                 hexcolor.green = (tcolors[t]->g) << 8;
  425.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  426.                 RGBForeColor(&hexcolor);
  427.                 PaintRgn(rgn);
  428.                 /* Restore the previous color. */
  429.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  430.                 RGBForeColor(&oldcolor);
  431.             } else {
  432.             }
  433.         } else {
  434.         }
  435.     }
  436.     /* Maybe overlay the cell. */
  437.     if (t2 < 0) {
  438.         if (t2 == -1) {
  439.             PenPat(QDPat(ltGray));
  440.             PenMode(patOr);
  441.         } else if (t2 == -2) {
  442.             PenPat(QDPat(gray));
  443. /*                PenMode(patBic);  */
  444.             PenMode(notPatOr);
  445.         }
  446.         PaintRgn(rgn);
  447.         PenNormal();
  448.     }
  449. }
  450.  
  451. /* Draw a set of borders for the given position. */
  452.  
  453. void
  454. draw_border_line_multiple(WindowPtr win, int sx, int sy, int bitmask, int power, int t, int angle)
  455. {
  456.     int wid = bwid[power], wid2, dir, tweakedcolor = FALSE;
  457.     int sx1, sy1, sx2, sy2;
  458.     Image *timg;
  459.     MacImage *mactimg;
  460.     RGBColor cellcolor, oldcolor;                
  461.  
  462.     if (wid == 0)
  463.       return;
  464.     wid2 = wid / 2;
  465.     if (0 /* power == 4*/) {
  466.         Rect srcrect, destrect;
  467.         BitMap *winbits;
  468.  
  469.         winbits = &(((GrafPtr) win)->portBits);
  470.         SetRect(&srcrect, 0, 0, 32, 32);
  471.         SetRect(&destrect, sx, sy, sx+32, sy+32);
  472.         CopyBits(&(bordbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
  473.         return;
  474.     }
  475.     PenSize(wid, wid);
  476.     /* Decide on the line color/pattern to use. */
  477.     timg = best_image(timages[t], wid, wid);
  478.     if (timg && timg->hook) {
  479.         mactimg = (MacImage *) timg->hook;
  480.         if (hasColorQD) {
  481.             if (mactimg->colrpat && (maxscreendepth > 1 || !mactimg->patdefined)) {
  482.                 PenPixPat(mactimg->colrpat);
  483.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  484.                 /* A solid color is preferable to a b/w pattern. */
  485.                 cellcolor.red   = (tcolors[t]->r) << 8;
  486.                 cellcolor.green = (tcolors[t]->g) << 8;
  487.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  488.                 RGBForeColor(&cellcolor);
  489.                 tweakedcolor = TRUE;
  490.             } else {
  491.                 PenPat(IMG_PAT(mactimg));
  492.             }
  493.         } else {
  494.             PenPat(IMG_PAT(mactimg));
  495.         }
  496.     } else {
  497.         if (hasColorQD) {
  498.             if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  499.                 /* A solid color is preferable to gray. */
  500.                 cellcolor.red   = (tcolors[t]->r) << 8;
  501.                 cellcolor.green = (tcolors[t]->g) << 8;
  502.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  503.                 RGBForeColor(&cellcolor);
  504.                 tweakedcolor = TRUE;
  505.             } else {
  506.                 PenPat(QDPat(dkGray));
  507.             }
  508.         } else {
  509.             PenPat(QDPat(dkGray));
  510.         }
  511.     }
  512.     for_all_directions(dir) {
  513.         if (bitmask & (1 << dir)) {
  514.             /* Actually draw the line. */
  515.             sx1 = bsx[power][dir];  sy1 = bsy[power][dir];
  516.             if (angle == 30) {
  517.                 sy1 /= 2;
  518.             } else if (angle == 15) {
  519.                 sy1 /= 4;
  520.             }
  521.             MoveTo(sx + sx1 - wid2, sy + sy1 - wid2);
  522.             sx2 = bsx[power][dir+1];  sy2 = bsy[power][dir+1];
  523.             if (angle == 30) {
  524.                 sy2 /= 2;
  525.             } else if (angle == 15) {
  526.                 sy2 /= 4;
  527.             }
  528.             LineTo(sx + sx2 - wid2, sy + sy2 - wid2);
  529.         }
  530.     }
  531.     PenNormal();
  532.     if (hasColorQD && tweakedcolor) {
  533.         /* Restore the previous color. */
  534.         oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  535.         RGBForeColor(&oldcolor);
  536.     }
  537. }
  538.  
  539. /* Draw a set of connections for the given ttype and given cell. */
  540.  
  541. void
  542. draw_connection_line_multiple(WindowPtr win, int sx, int sy, int bitmask, int power, int t, int angle)
  543. {
  544.     int dir, wid = cwid[power], lh, ly, xoff, yoff, tweakedcolor = FALSE;
  545.     Image *timg;
  546.     MacImage *mactimg;
  547.     RGBColor cellcolor, oldcolor;                
  548.  
  549.     if (wid == 0)
  550.       return;
  551.     if (0 /*power == 4*/) {
  552.         Rect srcrect, destrect;
  553.         BitMap *winbits;
  554.  
  555.         winbits = &(((GrafPtr) win)->portBits);
  556.         SetRect(&srcrect, 0, 0, 32, 32);
  557.         SetRect(&destrect, sx, sy, sx+32, sy+32);
  558.         CopyBits(&(connbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
  559.         return;
  560.     }
  561.     PenSize(wid, wid);
  562.     timg = best_image(timages[t], wid, wid);
  563.     if (timg && timg->hook) {
  564.         mactimg = (MacImage *) timg->hook;
  565.         if (hasColorQD) {
  566.             if (mactimg->colrpat && (maxscreendepth > 1 || !mactimg->patdefined)) {
  567.                 PenPixPat(mactimg->colrpat);
  568.             } else if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  569.                 /* A solid color is preferable to a b/w pattern. */
  570.                 cellcolor.red   = (tcolors[t]->r) << 8;
  571.                 cellcolor.green = (tcolors[t]->g) << 8;
  572.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  573.                 RGBForeColor(&cellcolor);
  574.                 tweakedcolor = TRUE;
  575.             } else {
  576.                 PenPat(IMG_PAT(mactimg));
  577.             }
  578.         } else {
  579.             PenPat(IMG_PAT(mactimg));
  580.         }
  581.     } else {
  582.         if (hasColorQD) {
  583.             if (tcolors[t] != NULL && tcolors[t]->defined && minscreendepth > 1) {
  584.                 /* A solid color is preferable to gray. */
  585.                 cellcolor.red   = (tcolors[t]->r) << 8;
  586.                 cellcolor.green = (tcolors[t]->g) << 8;
  587.                 cellcolor.blue  = (tcolors[t]->b) << 8;
  588.                 RGBForeColor(&cellcolor);
  589.                 tweakedcolor = TRUE;
  590.             } else {
  591.                 PenPat(QDPat(gray));
  592.             }
  593.         } else {
  594.             PenPat(QDPat(gray));
  595.         }
  596.     }
  597.     lh = hhs[power];
  598.     if (angle == 30)
  599.       lh /= 4;
  600.     else if (angle == 15)
  601.       lh /= 8;
  602.     else
  603.       lh /= 2;
  604.     xoff = hws[power] / 2 - wid / 2;
  605.     yoff = lh - wid / 2;
  606.     for_all_directions(dir) {
  607.         if (bitmask & (1 << dir)) {
  608.             MoveTo(sx + xoff, sy + yoff);
  609.             ly = lsy[power][dir];
  610.             if (angle == 30)
  611.               ly /= 2;
  612.             else if (angle == 15)
  613.               ly /= 4;
  614.             Line(lsx[power][dir], ly);
  615.         }
  616.     }
  617.     PenNormal();
  618.     if (hasColorQD && tweakedcolor) {
  619.         /* Restore the previous color. */
  620.         oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  621.         RGBForeColor(&oldcolor);
  622.     }
  623. }
  624.  
  625. /* This draws a type of terrain in a way that indicates its subtype. */
  626.  
  627. void
  628. draw_terrain_sample(WindowPtr win, Rect tmprect, int t)
  629. {
  630.     switch (t_subtype(t)) {
  631.         case cellsubtype:
  632.             draw_hex_region(tmprect.left, tmprect.top, 4, FALSE, t, 0, 90);
  633.             break;
  634.         case bordersubtype:
  635.             draw_border_line_multiple(win, tmprect.left, tmprect.top, -1, 4, t, 90);
  636.             break;
  637.         case connectionsubtype:
  638.             draw_connection_line_multiple(win, tmprect.left, tmprect.top, -1, 4, t, 90);
  639.             break;
  640.         case coatingsubtype:
  641.             draw_hex_region(tmprect.left, tmprect.top, 4, FALSE, t, 0, 90);
  642.             /* Make it a 50% pattern. (should make more obvious somehow?) */
  643.             gray_out_rect(&tmprect);
  644.             break;
  645.         default:
  646.             terrain_subtype_warning("draw sample", t);
  647.             break;
  648.     }
  649. }
  650.  
  651. /* Draw a set of country border at the given position. */
  652.  
  653. void
  654. draw_country_borders(WindowPtr win, int sx, int sy, int bitmask, int power, int shade, int angle)
  655. {
  656.     int wid = bwid2[power], wid2, dir, dx1, dy1;
  657.  
  658.     if (wid == 0)
  659.       return;
  660.     PenSize(wid, wid);
  661.     if (shade == 0)
  662.       PenPat(QDPat(black));
  663.     if (shade == 2)
  664.       PenPat(QDPat(gray));
  665.     wid2 = wid / 2;
  666.     for_all_directions(dir) {
  667.         if (bitmask & (1 << dir)) {
  668.             dx1 = bsx[power][dir];  dy1 = bsy[power][dir];
  669.             if (angle == 30) { dy1 /= 2; }
  670.             if (angle == 15) { dy1 /= 4; }
  671.             MoveTo(sx + dx1 - wid2, sy + dy1 - wid2);
  672.             dx1 = bsx[power][dir+1];  dy1 = bsy[power][dir+1];
  673.             if (angle == 30) { dy1 /= 2; }
  674.             if (angle == 15) { dy1 /= 4; }
  675.             LineTo(sx + dx1 - wid2, sy + dy1 - wid2);
  676.         }
  677.     }
  678.     PenNormal();
  679. }
  680.  
  681. /* Draw a set of theater borders at the given position. */
  682.  
  683. void
  684. draw_ai_region_borders(WindowPtr win, int sx, int sy, int bitmask, int power)
  685. {
  686.     int wid, wid2, dir;
  687.     Rect tmprect;
  688.  
  689.     if (bwid[power] > 0) {
  690.         wid = 2;
  691.         wid2 = 1;
  692.         PenSize(wid, wid);
  693.         for_all_directions(dir) {
  694.             if (bitmask & (1 << dir)) {
  695.                 MoveTo(sx + bsx[power][dir] - wid2 + 1, sy + bsy[power][dir] - wid2 + 1);
  696.                 LineTo(sx + bsx[power][dir+1] - wid2 + 1, sy + bsy[power][dir+1] - wid2 + 1);
  697.             }
  698.         }
  699.         PenMode(notPatCopy);
  700.         for_all_directions(dir) {
  701.             if (bitmask & (1 << dir)) {
  702.                 MoveTo(sx + bsx[power][dir] - wid2, sy + bsy[power][dir] - wid2);
  703.                 LineTo(sx + bsx[power][dir+1] - wid2, sy + bsy[power][dir+1] - wid2);
  704.             }
  705.         }
  706.         PenNormal();
  707.     } else {
  708.         SetRect(&tmprect, sx, sy, sx + hws[power], sy + hhs[power]);
  709.         OffsetRect(&tmprect, 1, 1);
  710.         FillRect(&tmprect, QDPat(black));
  711.         OffsetRect(&tmprect, -1, -1);
  712.         FillRect(&tmprect, QDPat(white));
  713.     }
  714. }
  715.  
  716. int
  717. draw_elevation_here(int x, int y)
  718. {
  719.     return terrain_visible(dside, x, y);
  720. }
  721.  
  722. /* Indicate the elevation of the given location, textually for now. */
  723.  
  724. void
  725. draw_elevation(int sx, int sy, int power, int elev)
  726. {
  727.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  728.     if (elev != 0) {
  729.         sprintf(spbuf, "%d", elev);
  730.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  731.     }
  732. }
  733.  
  734. /* Don't draw the temperature in every cell, only do ones with even coords or
  735.    ones where the temperature in any adjacent cell is different. */
  736.  
  737. int
  738. draw_temperature_here(int x, int y)
  739. {
  740.     int dir, x1, y1, temphere = temperature_view(dside, x, y);
  741.  
  742. #ifdef DESIGNERS
  743.     /* Designers should see temperature in every cell. */
  744.     if (dside->designer)
  745.       return TRUE;
  746. #endif /* DESIGNERS */
  747.     for_all_directions(dir) {
  748.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  749.             if (temphere != temperature_view(dside, x1, y1))
  750.               return TRUE;
  751.             /* Always show temperature around edge of known area. */
  752.             if (terrain_view(dside, x1, y1) == UNSEEN)
  753.               return TRUE;
  754.         }
  755.     }
  756.     return (x % 2 == 0 && y % 2 == 0);
  757. }
  758.  
  759. /* Indicate the temperature of the given location, textually for now. */
  760.  
  761. void
  762. draw_temperature(int sx, int sy, int power, int temp)
  763. {
  764.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  765.     if (1 /* draw as text */) {
  766.         sprintf(spbuf, "%d°", temp);  /* (should do char more portably) */
  767.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  768.     }
  769.     /* (Also draw isotherms eventually) */
  770. }
  771.  
  772. int
  773. draw_clouds_here(int x, int y)
  774. {
  775.     /* Draw clouds in every cell always. */
  776.     return TRUE;
  777. }
  778.  
  779. void
  780. draw_clouds(int sx, int sy, int power, int cloudtype)
  781. {
  782.     Rect tmprect;
  783.  
  784.     /* Don't draw clear sky. */
  785.     if (cloudtype == 0)
  786.       return;
  787.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  788.     SetRect(&tmprect, sx - hws[power] / 2, sy - hhs[power] / 2, sx + hws[power] / 2, sy + hhs[power] / 2);
  789.     /* Should use pat# 130 patterns for this instead. */
  790.     PenPat(cloudtype >= 3 ? QDPat(dkGray) : (cloudtype == 2 ? QDPat(gray) : QDPat(ltGray)));
  791.     PenMode(patBic);
  792.     PaintOval(&tmprect);
  793.     PenNormal();
  794. }
  795.  
  796. /* Don't draw the winds in every cell, only do ones with odd coords or
  797.    ones where the wind in any adjacent cell is different. */
  798. /* (generic routine?) */
  799.  
  800. int
  801. draw_winds_here(int x, int y)
  802. {
  803.     int dir, x1, y1, windhere = wind_view(dside, x, y);
  804.  
  805. #ifdef DESIGNERS
  806.     /* Designers should see wind in every cell. */
  807.     if (dside->designer)
  808.       return TRUE;
  809. #endif /* DESIGNERS */
  810.     for_all_directions(dir) {
  811.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  812.             if (windhere != wind_view(dside, x1, y1))
  813.               return TRUE;
  814.             /* Always show wind around edge of known area. */
  815.             if (terrain_view(dside, x1, y1) == UNSEEN)
  816.               return TRUE;
  817.         }
  818.     }
  819.     return (x % 2 == 1 && y % 2 == 1);
  820. }
  821.  
  822. /* Indicate the given wind at the given location. */
  823.  
  824. void
  825. draw_winds(int sx, int sy, int power, int rawwind)
  826. {
  827.     int i, wdir = wind_dir(rawwind), wforce = wind_force(rawwind);
  828.     GrafPtr curport;
  829.  
  830.     sx += (hws[power] - 16) / 2;  sy += (hhs[power] - 16) / 2;
  831.     if (wforce < 0) {
  832.         DGprintf("negative wind force %d, substituting 0", wforce);
  833.         wforce = 0;
  834.     }
  835.     /* (should use overall max/mins to compute scaling factor) */
  836.     if (wforce > 4)
  837.       wforce = 4;
  838.     if (wforce == 0)
  839.       wdir = 0;
  840.     /* Collect sicns if not already in. */
  841.     if (numwindsicns == 0) {
  842.         for (i = 0; i <= 4; ++i) {
  843.             windsicnhandle[i] = GetResource('SICN', sicnWinds0 + i);
  844.         }
  845.         numwindsicns = 5;
  846.     }
  847.     GetPort(&curport);
  848.     /* Draw an offset white version, for contrast. */
  849.     plot_sicn(curport, sx + 1, sy + 1, windsicnhandle[wforce], wdir, FALSE, srcBic);
  850.     plot_sicn(curport, sx, sy, windsicnhandle[wforce], wdir, FALSE, srcOr);
  851. }
  852.  
  853. /* Draw the view coverage of a cell (for debugging). */
  854.  
  855. void
  856. draw_coverage(int sx, int sy, int power, int cov, int altcov)
  857. {
  858.     char buf[40];
  859.  
  860.     buf[0] = '\0';
  861.     if (cov > 0) {
  862.         tprintf(buf, ":%d:", cov);
  863.     }
  864.     if (altcov > -1) {
  865.         tprintf(buf, ",%d:", altcov);
  866.     }
  867.     if (buf[0] != '\0') {
  868.         /* Adjust to the lower left corner of the cell. */
  869.         sx += 2;  sy += hcs[power] - 2;
  870.         draw_legend_text(sx, sy, hhs[power] / 2, buf, -1);
  871.     }
  872. }
  873.  
  874. /* Draw a unit's name, if it has one. */
  875.  
  876. void
  877. draw_unit_name(Unit *unit, int sx, int sy, int sw, int sh)
  878. {
  879.     if (unit->name) {
  880.         draw_legend_text(sx + sw + 1, sy + sh/2, sh, unit->name, -1);
  881.     }
  882. }
  883.  
  884. void
  885. draw_legend_text(int sx, int sy, int sh, char *legend, int just)
  886. {
  887.     int strwid, strleft;
  888.     Rect maskrect;
  889.     FontInfo fontinfo;
  890.     
  891.     /* Scale text sizes to fit in smaller cells if necessary. */
  892.     TextSize(min(max(5, sh), 10));
  893.     strwid = TextWidth(legend, 0, strlen(legend));
  894.     if (just < 0) {
  895.         strleft = sx;
  896.     } else if (just > 0) {
  897.         strleft = sx - strwid;
  898.     } else {
  899.         strleft = sx - strwid / 2;
  900.     }
  901.     MoveTo(strleft, sy);
  902.     if (0) {
  903.         /* Make it readable against a noisy background. */
  904. /*        TextFace(bold|outline); */
  905.         TextMode(srcBic);
  906.     } else {
  907.         /* This makes a big white box for name, less attractive but easier to read. */
  908.         GetFontInfo(&fontinfo);
  909.         maskrect.top = sy - fontinfo.ascent;
  910.         /* Ensure a one pixel strip of white all along the top. */
  911.         maskrect.top += 1;
  912.         maskrect.left = strleft - 1;
  913.         maskrect.bottom = sy + fontinfo.descent;
  914.         /* Ensure a one pixel strip of white all along the bottom, even below descenders. */
  915.         maskrect.bottom += 1;
  916.         maskrect.right = maskrect.left + strwid + 1;
  917.         FillRect(&maskrect, QDPat(white));
  918.     }
  919.     DrawText(legend, 0, strlen(legend));
  920. }
  921.  
  922.  
  923. void
  924. draw_blast_image(WindowPtr win, int sx, int sy, int sw, int sh, int blasttype)
  925. {
  926.     int i;
  927.     Rect tmprect;
  928.     Rect srcrect, imagerect;
  929.     BitMap bm, *winbits;
  930.     GrafPtr curport;
  931.  
  932.     /* Collect sicns if not already in. */
  933.     if (numblastsicns == 0) {
  934.         for (i = 0; i <= 2; ++i) {
  935.             blastsicnhandle[i] = GetResource('SICN', sicnMiss + i);
  936.             ++numblastsicns;
  937.         }
  938.     }
  939.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  940.     if (sw >= 16) {
  941.         winbits = &(((GrafPtr) win)->portBits);
  942.         imagerect.top = sy;  imagerect.left = sx;
  943.         imagerect.bottom = imagerect.top + sh;  imagerect.right = imagerect.left + sw;
  944.         /* should save image under here, then draw blast */
  945.         GetPort(&curport);
  946.         SetRect(&srcrect, 0, 0, 16, 16);
  947.         bm.rowBytes = 2;
  948.         bm.bounds = srcrect;
  949.         bm.baseAddr = *(blastsicnhandle[blasttype]);
  950.         if (hasColorQD) {
  951.             RGBColor tmpcolor;
  952.  
  953.             OffsetRect(&imagerect, 1, 1);
  954.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  955.             tmpcolor.red = 60000;  tmpcolor.green = tmpcolor.blue = 0;
  956.             RGBForeColor(&tmpcolor);
  957.             OffsetRect(&imagerect, -1, -1);
  958.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  959.             /* Restore the previous color. */
  960.             tmpcolor.red = tmpcolor.green = tmpcolor.blue = 0;
  961.             RGBForeColor(&tmpcolor);
  962.         } else {
  963.             OffsetRect(&imagerect, 1, 1);
  964.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  965.             OffsetRect(&imagerect, -1, -1);
  966.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  967.         }
  968.     } else {
  969.         InvertRect(&tmprect);
  970.     }
  971. }
  972.  
  973. void
  974. clear_blast_image(WindowPtr win, int sx, int sy, int sw, int sh, int blasttype)
  975. {
  976.     Rect tmprect;
  977.  
  978.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  979.     if (sw >= 16) {
  980.         /* should restore image under here */
  981.     } else {
  982.         InvertRect(&tmprect);
  983.     }
  984. }
  985.  
  986. int
  987. picture_width(PicHandle pichandle)
  988. {
  989.     return ((*pichandle)->picFrame.right - (*pichandle)->picFrame.left);
  990. }
  991.  
  992. int
  993. picture_height(PicHandle pichandle)
  994. {
  995.     return ((*pichandle)->picFrame.bottom - (*pichandle)->picFrame.top);
  996. }
  997.  
  998. /* Generic sicn drawer. */
  999.  
  1000. void
  1001. plot_sicn(WindowPtr win, int sx, int sy, Handle sicnhandle, int n, int erase, int mode)
  1002. {
  1003.     Rect srcrect, imagerect;
  1004.     BitMap bm, *winbits;
  1005.  
  1006.     if (sicnhandle == nil)
  1007.       return;
  1008.     imagerect.left = sx;  imagerect.top = sy;
  1009.     imagerect.right = imagerect.left + 16;  imagerect.bottom = imagerect.top + 16;
  1010.     winbits = &(((GrafPtr) win)->portBits);
  1011.     SetRect(&srcrect, 0, 0, 16, 16);
  1012.     bm.rowBytes = 2;
  1013.     bm.bounds = srcrect;
  1014.     if (erase)
  1015.       EraseRect(&imagerect);
  1016.     bm.baseAddr = *(sicnhandle) + 32 * n;
  1017.     CopyBits(&bm, winbits, &srcrect, &imagerect, mode, nil);
  1018. }
  1019.  
  1020. /* Given a rectangle, make half of its pixels white. */
  1021.  
  1022. void
  1023. gray_out_rect(Rect *rectptr)
  1024. {
  1025.     PenPat(QDPat(gray));
  1026.     PenMode(patBic);
  1027.     PaintRect(rectptr);
  1028.     PenNormal();
  1029. }
  1030.